package top.haijunit.navi.auth.service;

import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import top.haijunit.framework.core.exception.ExceptionServer;
import top.haijunit.navi.auth.domain.PermissionConvert;
import top.haijunit.navi.auth.domain.PermissionInfo;
import top.haijunit.navi.auth.domain.PermissionRelationInfo;
import top.haijunit.navi.auth.entity.PermissionEntity;
import top.haijunit.navi.auth.entity.PermissionGroupEntity;
import top.haijunit.navi.auth.entity.PermissionRelationEntity;
import top.haijunit.navi.auth.mapper.PermissionGroupMapper;
import top.haijunit.navi.auth.mapper.PermissionMapper;

import java.util.*;

/**
 * 权限服务
 *
 * @author zhanghaijun
 * @since 2024-08-30
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PermissionService extends ServiceImpl<PermissionMapper, PermissionEntity> {

    private final PermissionRelationService permissionRelationService;
    private final PermissionGroupMapper groupMapper;
    private final PermissionConvert converter;

    /**
     * 获取权限列表
     */
    public List<PermissionInfo> selectList(PermissionInfo info) {
        QueryWrapper<PermissionEntity> query = new QueryWrapper<>();
        if (null != info) {
            query.eq(CharSequenceUtil.isNotBlank(info.getGroupCode()), "p.group_code", info.getGroupCode());
            query.like(CharSequenceUtil.isNotBlank(info.getGroupName()), "g.name", info.getGroupName());
            query.likeLeft(CharSequenceUtil.isNotBlank(info.getCode()), "p.uniqCode", info.getCode());
            query.like(CharSequenceUtil.isNotBlank(info.getPermissionName()), "p.name", info.getPermissionName());
            query.eq(null != info.getPermissionLevel() && 0 < info.getPermissionLevel(), "p.level", info.getPermissionLevel());
        }
        return baseMapper.selectPermissionList(query);
    }

    /**
     * 获取所有的权限关联关系
     */
    public List<PermissionRelationEntity> getPermissionRelationList() {
        return this.baseMapper.selectPermissionRelationList(new LambdaQueryWrapper<>());
    }

    /**
     * 添加权限
     */
    @Transactional(rollbackFor = Exception.class)
    public Long insert(PermissionRelationInfo info) {
        Assert.hasLength(info.getGroupCode(), "权限组编码不能为空");
        if (!groupMapper.exists(new LambdaQueryWrapper<PermissionGroupEntity>().eq(PermissionGroupEntity::getPermissionGroupId, info.getGroupCode()))) {
            throw new ExceptionServer("权限组不存在!");
        }
        Assert.hasLength(info.getPermissionName(), "权限名称不能为空");
        if (this.exists(new LambdaQueryWrapper<PermissionEntity>().eq(PermissionEntity::getPermissionName, info.getPermissionName()))) {
            throw new ExceptionServer("权限名称已存在，请更换名称！");
        }
        Assert.hasLength(info.getCode(), "权限编码不能为空");
        if (CharSequenceUtil.splitTrim(info.getCode(), ":").size() != 3) {
            throw new ExceptionServer("权限编码格式（[模块:功能:操作]）错误，请重新输入！");
        }
        if (this.exists(new LambdaQueryWrapper<PermissionEntity>().eq(PermissionEntity::getPermissionId, info.getCode()))) {
            throw new ExceptionServer("权限编码已存在，请更换编码！");
        }
        PermissionEntity positionEntity = converter.convert(info);
        this.baseMapper.insert(positionEntity);
        // 更新权限之间的关系
        permissionRelationService.updatePermissionRelation(positionEntity.getPermissionId(), info.getRepelList(), info.getDependList());
        return positionEntity.getPermissionId();
    }

    /**
     * 删除权限
     */
    public Long delete(Long code) {
        // 删除权限
        this.baseMapper.delete(new LambdaQueryWrapper<PermissionEntity>().eq(PermissionEntity::getPermissionId, code));
        // 删除权限之间的关系
        permissionRelationService.deletePermissionRelation(code);
        return code;
    }

    /**
     * 检查权限冲突
     */
    public void checkPermissionConflicts(Collection<Long> permissionCodes) {
        // 权限的关联关系数据
        Map<Long, List<PermissionRelationEntity>> permissionRelationMap = preprocessPermissionRelations();

        for (Long permissionCode : permissionCodes) {
            List<PermissionRelationEntity> relationList = permissionRelationMap.getOrDefault(permissionCode, Collections.emptyList());
            for (PermissionRelationEntity relation : relationList) {
                switch (relation.getRelationType()) {
                    case 1: // 互斥
                        if (permissionCodes.contains(relation.getRelationPermissionCode())) {
                            throw new ExceptionServer(String.format("权限冲突：%s -> %s", permissionCode, relation.getRelationPermissionCode()));
                        }
                        break;
                    case 2: // 依赖
                        if (!permissionCodes.contains(relation.getRelationPermissionCode())) {
                            throw new ExceptionServer(String.format("权限依赖不足: %s -> %s", permissionCode, relation.getRelationPermissionCode()));
                        }
                        break;
                    default:
                        throw new ExceptionServer(String.format("未知的权限关联类型: %s -> %s", permissionCode, relation.getRelationPermissionCode()));
                }
            }
        }
    }

    public void checkPermissionListExclusion(Set<Long> permissionCodes, Set<Long> excludedPermissionCodes) {
        Map<Long, List<PermissionRelationEntity>> relationMap = preprocessPermissionRelations();
        for (Long code : permissionCodes) {
            List<PermissionRelationEntity> relationEntities = relationMap.getOrDefault(code, Collections.emptyList());
            for (PermissionRelationEntity entity : relationEntities) {
                if (excludedPermissionCodes.contains(entity.getRelationPermissionCode())) {
                    throw new ExceptionServer("权限冲突：%s -> %s", code, entity.getRelationPermissionCode());
                }
            }
        }
    }

    /**
     * 权限的关联关系预处理
     */
    private Map<Long, List<PermissionRelationEntity>> preprocessPermissionRelations() {
        LambdaQueryWrapper<PermissionRelationEntity> wrapper = new LambdaQueryWrapper<>();
        List<PermissionRelationEntity> permissionRelationEntities = this.baseMapper.selectPermissionRelationList(wrapper);
        Map<Long, List<PermissionRelationEntity>> permissionCodeToRelations = new HashMap<>();
        for (PermissionRelationEntity entity : permissionRelationEntities) {
            permissionCodeToRelations.computeIfAbsent(entity.getPermissionCode(), k -> new ArrayList<>()).add(entity);
        }
        return permissionCodeToRelations;
    }
}
